
#include "EventLoop.h"
#include "Channel.h"
#include "Epoller.h"
#include "Logger.h"

int EventLoop::CreateWakeupFd() {
    int event_fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
    if (event_fd < 0) {
        abort();
    }
    LOG_INFO("Create a eventfd = %d", event_fd);
    return event_fd;
}

// 唤醒 subloop
void EventLoop::ReadWakeupFd() {
    uint64_t res = 0;
    ssize_t ret = read(wakeup_fd_, &res, sizeof(uint64_t));
    if (ret < 0) {
        // EINTR -- 被信号打断；EAGAIN -- 表示无数据可读
        if (errno == EINTR || errno == EAGAIN) {
            return;
        }
        abort();
    }
}

void EventLoop::WriteWakeupFd() {
    uint64_t res = 0;
    ssize_t ret = write(wakeup_fd_, &res, sizeof(uint64_t));
    if (ret < 0) {
        if (errno == EINTR) {
            return;
        }
        abort();
    }
}

void EventLoop::DoPendingFunctors() {
    std::vector<Functor> temp_tasks;
    // 作用域中加锁，离开作用域自动解锁
    {
        std::unique_lock<std::mutex> lock(mutex_);
        temp_tasks.swap(tasks_);
    }
    for (auto& Functor : temp_tasks) {
        Functor();
    }
}

/*
thread_id_：在 EventLoop 对象构造时，记录创建该对象的线程ID
std::this_thread::get_id()：获取当前执行代码的线程ID
*/
bool EventLoop::IsInLoop() {
    return thread_id_ == std::this_thread::get_id();
}

void EventLoop::RunInLoop(const Functor cb) {
    if (IsInLoop())
        return cb();
    else
        QueueInLoop(cb);
}

void EventLoop::QueueInLoop(const Functor cb) {
    LOG_INFO("queue in a callback to tasks.");
    {
        std::unique_lock<std::mutex> lock(mutex_);
        tasks_.emplace_back(cb);
    }
    if (!IsInLoop()) {
        WriteWakeupFd();
    }
}

EventLoop::EventLoop()
    : thread_id_(std::this_thread::get_id()),
      wakeup_fd_(CreateWakeupFd()),
      epoller_(new Epoller(this)),
      wakeup_channel_(new Channel(wakeup_fd_, this)),
      looping_(false),
      quit_(false) {
    wakeup_channel_->SetReadCallback(std::bind(&EventLoop::ReadWakeupFd, this));
    wakeup_channel_->EnableRead();
}

void EventLoop::Loop() {
    looping_ = true;
    quit_ = false;
    while (!quit_) {
        // 拿到了它的Poller给返回的所有发生事件的channel列表
        std::vector<Channel*> active_channels;
        // 阻塞等待，直到有文件描述符就绪（可读、可写、错误等）
        epoller_->EpollWait(&active_channels);
        // 每个 Channel 处理自己的事件
        for (auto& channel : active_channels) {
            LOG_INFO("sock:%d hadle its events...", channel->Fd());
            channel->HandleEvent();
        }
        // 执行mainloop注册的回调函数 cb(s)
        DoPendingFunctors();
    }
    looping_ = false;
}

void EventLoop::Quit() {
    quit_ = true;
    if (!IsInLoop()) {
        WriteWakeupFd();
    }
}

void EventLoop::UpdateChannel(Channel* channel) {
    epoller_->UpdateChannel(channel);
}
void EventLoop::RemoveChannel(Channel* channel) {
    epoller_->RemoveChannel(channel);
}

EventLoop::~EventLoop() {
    if (wakeup_fd_)
        close(wakeup_fd_);
}
